package cn.ynrcb.personnelfile.sysadmin.controller;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.ynrcb.personnelfile.common.annotation.SysLog;
import cn.ynrcb.personnelfile.common.utils.R;
import cn.ynrcb.personnelfile.sysadmin.constant.SysConstant;
import cn.ynrcb.personnelfile.sysadmin.dao.SysUserDao;
import cn.ynrcb.personnelfile.sysadmin.entity.SysUserEntity;
import cn.ynrcb.personnelfile.sysadmin.form.SysLoginForm;
import cn.ynrcb.personnelfile.sysadmin.service.SysCaptchaService;
import cn.ynrcb.personnelfile.sysadmin.service.SysUserService;
import cn.ynrcb.personnelfile.sysadmin.service.SysUserTokenService;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.DynamicParameter;
import com.github.xiaoymin.knife4j.annotations.DynamicResponseParameters;
import io.swagger.annotations.*;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Map;

/**
 * 登录相关
 */
@Api(value = "整改需求系统系统", tags = {"系统相关=>登录相关接口"})
@RestController
public class SysLoginController extends AbstractController {
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysUserDao sysUserDao;
    @Autowired
    private SysUserTokenService sysUserTokenService;
    @Autowired
    private SysCaptchaService sysCaptchaService;
    @Autowired
    private Cache<String, Object> caffeineCache;

    /**
     * 检查验证码
     */
    @ApiOperation("检查验证码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "uuid", value = "uuid", example = "ba344601-5e09-435f-b65f-f974e23d305a", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "captcha", value = "验证码", example = "3fg4t", required = true, dataType = "String", paramType = "query")
    })
    @ApiResponses({
            @ApiResponse(code = 0, message = "验证码正确"),
            @ApiResponse(code = 2001, message = "验证码不正确！")
    })
    @GetMapping("/sys/check")
    public R checkCaptcha(String captcha, String uuid) {
        logger.info("获取验证码：" + captcha);
        boolean isCaptcha = sysCaptchaService.validate(uuid, captcha);
        if (!isCaptcha) {
            return R.error(2001, "验证码不正确！");
        }
        return R.ok();
    }

    /**
     * 验证码
     */
    @ApiOperation("验证码")
    @ApiImplicitParam(name = "uuid", value = "uuid", example = "ba344601-5e09-435f-b65f-f974e23d305a", required = true, dataType = "String", paramType = "query")
    @GetMapping("captcha")
    public void captcha(HttpServletResponse response, String uuid) throws IOException {
        response.setHeader("Cache-Control", "no-store, no-cache");
        response.setContentType("image/jpeg");

        //获取图片验证码
        BufferedImage image = sysCaptchaService.getCaptcha(uuid);

        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(image, "jpg", out);
        IOUtils.closeQuietly(out);
    }

    /**
     * base64验证码
     */
    @ApiOperation("base64验证码")
    @ApiImplicitParam(name = "uuid", value = "uuid", example = "ba344601-5e09-435f-b65f-f974e23d305a", required = true, dataType = "String", paramType = "query")
    @GetMapping("base64captcha")
    public String base64captcha(HttpServletResponse response, String uuid) throws IOException {

        //获取图片验证码
        BufferedImage image = sysCaptchaService.getCaptcha(uuid);

        //图片转base64
        ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
        ImageIO.write(image,"jpg",outputStream);
        byte[] bytes=outputStream.toByteArray();
        String base64String= Base64.encodeBase64String(bytes);
        logger.info("验证码转base64" + base64String);
        return base64String;
    }

    /**
     * 登录
     */
    @ApiOperation("登录")
    @SysLog("用户登录")
    @PostMapping("/sys/login")
    @ApiOperationSupport(
            responses = @DynamicResponseParameters(properties = {
                    @DynamicParameter(value = "状态码", name = "code", example = "0"),
                    @DynamicParameter(value = "信息", name = "msg", example = "success"),
                    @DynamicParameter(value = "token", name = "token"),
                    @DynamicParameter(value = "token过期时间", name = "expire")
            })
    )
    @ApiResponses({
            @ApiResponse(code = 2001, message = "验证码不正确！"),
            @ApiResponse(code = 2002, message = "用户名或密码不正确！"),
            @ApiResponse(code = 2003, message = "账号未注册！"),
            @ApiResponse(code = 2004, message = "账号已停用，请联系管理员！"),
            @ApiResponse(code = 2005, message = "账号已被锁定，请联系管理员！")
    })
    public Map<String, Object> login(@RequestBody SysLoginForm form) throws IOException {
        boolean captcha = sysCaptchaService.validate(form.getUuid(), form.getCaptcha());
        if (!captcha) {
            return R.error(2001, "验证码不正确！");
        }
        //系统支持用户名和绑定手机号混合登录
        //先查找用户名，没有查找到则查找手机号
        SysUserEntity user = sysUserService.queryByUserName(form.getUsername().trim());
        if (null == user) {
            user = sysUserService.queryByMobile(form.getUsername().trim());
        }
        //账号不存在
        if (null == user) {
            return R.error(2003, "账号未注册！");
        }
        //账号停用
        if (user.getStatus() == 0) {
            return R.error(2004, "账号已停用，请联系管理员！");
        }
        // 账号锁定
        if (user.getIsLock() == 1) {
            return R.error(2005, "账号已锁定，请联系管理员！");
        }
        // 账号待审核
        if (user.getAuditStatus() == 2) {
            return R.error(2006, "账号待审核，请耐心等待，有疑问可联系管理员！");
        }

        //账号密码错误
        boolean flag = false;
        flag = user.getPassword().equals(new Sha256Hash(form.getPassword(), user.getSalt()).toHex());

        if (!flag) {
            Object sysUserLoginCache = caffeineCache.asMap().get(SysConstant.SYS_USER_LOGIN + form.getUsername().trim());
            int loginFailCount = Convert.toInt(sysUserLoginCache, 0) + 1;    // 用户的登录失败次数
            caffeineCache.put(SysConstant.SYS_USER_LOGIN + form.getUsername().trim(), loginFailCount);
            if (loginFailCount >= SysConstant.SYS_USER_LOGIN_FAIL_MAX_COUNT) {
                user.setIsLock(1);
                sysUserService.updateById(user);
            }
            return R.error(2002, "账号或密码不正确，剩余" + (SysConstant.SYS_USER_LOGIN_FAIL_MAX_COUNT - loginFailCount) + "次登录机会！");
        }
        //生成token，并保存到数据库
        return sysUserTokenService.createToken(user.getUserId());
    }

    /**
     * 退出
     */
    @PostMapping("/sys/logout")
    public R logout() {
        sysUserTokenService.logout(getUserId());
        return R.ok();
    }

    /**
     * 根据用户名查询用户密码和盐是否存在
     *
     * @param username
     * @return
     */
    @GetMapping("/getByUsername")
    public R getByUsername(String username) {
        SysUserEntity sysUser = sysUserService.queryByUserName(username);
        if (ObjectUtil.isNotNull(sysUser) && (StringUtils.isBlank(sysUser.getPassword()) || StringUtils.isBlank(sysUser.getSalt()))) {
            return R.error(404, "您当前还未设置密码，请点击“忘记密码”设置后再进行登录。");
        }
        return R.ok();
    }

}
